package com.babayetu.myclang03grammaranalysis.lexical;

import com.babayetu.myclang03grammaranalysis.model.DFAState;
import com.babayetu.myclang03grammaranalysis.model.SimpleTokenReader;
import com.babayetu.myclang03grammaranalysis.model.Token;
import com.babayetu.myclang03grammaranalysis.model.TokenType;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;

import static com.babayetu.myclang03grammaranalysis.model.DFAState.*;
import static com.babayetu.myclang03grammaranalysis.utils.CharUtils.*;

@Slf4j
public class BasicLexer {
    private StringBuffer tmpTokenText = null;   //临时保存token的文本
    private List<Token> tokenList = null;       //保存解析出来的Token
    private Token<String> currentToken = null;        //当前正在解析的Token

    /**
     * 词法分析主函数
     * @param inputStr
     * @return
     */
    public SimpleTokenReader doParse(String inputStr) {
        tokenList = new ArrayList<>();

        tmpTokenText = new StringBuffer();
        currentToken = new Token<>();

        DFAState currentState = Initial;
        char c= 0;

        for (int i = 0; i <inputStr.length(); i++) {
            c= inputStr.charAt(i);
            switch (currentState) {
                case Initial:
                    currentState = initToken(c);
                break;
                case Id:
                    if (isAlpha(c) || isDigit(c)) {
                        tmpTokenText.append(c);
                    } else {
                        currentState = initToken(c);
                    }
                break;
                case GT:
                    if (c=='=') {
                        currentState = GE;
                        currentToken.setType(TokenType.GE);
                        tmpTokenText.append(c);
                    } else {
                        currentState = initToken(c);
                    }
                break;
                case GE:
                case Assignment:
                case Plus:
                case Minus:
                case Star:
                case Slash:
                case SemiColon:
                case LeftParen:
                case RightParen:
                    currentState = initToken(c);          //退出当前状态，并保存Token
                    break;
                case IntLiteral:
                    if (isDigit(c)) {
                        tmpTokenText.append(c);
                    } else {
                        currentState = initToken(c);
                    }
                break;
                case Id_int1:
                    if (c=='n') {
                        currentState = Id_int2;
                        tmpTokenText.append(c);
                    } else if (isAlpha(c) || isDigit(c)){
                        currentState = Id;
                        tmpTokenText.append(c);
                    } else {
                        currentState = initToken(c);
                    }
                break;
                case Id_int2:
                    if (c=='t') {
                        currentState = Id_int3;
                        tmpTokenText.append(c);
                    } else if (isAlpha(c) || isDigit(c)){
                        currentState = Id;
                        tmpTokenText.append(c);
                    } else {
                        currentState = initToken(c);
                    }
                break;
                case Id_int3:
                    if (isBlank(c)){
                        currentToken.setType(TokenType.Int);
                        currentState = initToken(c);
                    } else {
                        currentState = Id;
                        tmpTokenText.append(c);
                    }
                break;
                default:
                    log.info("default process char : {}, why go here?",c);
            }
        }

        if (tmpTokenText.length() > 0) {
            initToken(c);
        }

        return new SimpleTokenReader(tokenList);
    }

    //只做initial状态的第一步迁移逻辑
    private DFAState initToken(char c) {
        if (tmpTokenText.length() >0 ) {
            //临时字符缓冲区有字符
            currentToken.setValue(tmpTokenText.toString());
            tokenList.add(currentToken);

            currentToken = new Token<>();
            tmpTokenText = new StringBuffer();
        }

        DFAState newState = Initial;
        if (isAlpha(c)) {
            if (c =='i') {
                newState = Id_int1;
            } else {
                newState = Id;
            }

            currentToken.setType(TokenType.Identifier);
            tmpTokenText.append(c);
        } else if (isDigit(c)) {
            newState = IntLiteral;
            currentToken.setType(TokenType.IntLiteral);
            tmpTokenText.append(c);
        } else if (c == '>') {
            newState = GT;
            currentToken.setType(TokenType.GT);
            tmpTokenText.append(c);
        } else if (c == '+') {
            newState = Plus;
            currentToken.setType(TokenType.Plus);
            tmpTokenText.append(c);
        } else if (c == '-') {
            newState = Minus;
            currentToken.setType(TokenType.Minus);
            tmpTokenText.append(c);
        } else if (c == '*') {
            newState = Star;
            currentToken.setType(TokenType.Star);
            tmpTokenText.append(c);
        } else if (c == '/') {
            newState = Slash;
            currentToken.setType(TokenType.Slash);
            tmpTokenText.append(c);
        } else if (c == ';') {
            newState = SemiColon;
            currentToken.setType(TokenType.SemiColon);
            tmpTokenText.append(c);
        } else if (c == '(') {
            newState = LeftParen;
            currentToken.setType(TokenType.LeftParen);
            tmpTokenText.append(c);
        } else if (c == ')') {
            newState = RightParen;
            currentToken.setType(TokenType.RightParen);
            tmpTokenText.append(c);
        } else if (c == '=') {
            newState = Assignment;
            currentToken.setType(TokenType.Assignment);
            tmpTokenText.append(c);
        } else {
            newState = Initial; // skip all unknown patterns
        }

        return newState;
    }
}
